package com.lai.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lai.common.constant.CartConstant;
import com.lai.common.exception.BizCodeEnum;
import com.lai.common.exception.RRException;
import com.lai.common.to.SkuInfoTo;
import com.lai.common.to.UserInfoTo;
import com.lai.common.utils.R;
import com.lai.gulimall.cart.Interceptor.CartInterceptor;
import com.lai.gulimall.cart.feign.ProductFeignService;
import com.lai.gulimall.cart.service.CartService;
import com.lai.gulimall.cart.vo.CartItemVo;
import com.lai.gulimall.cart.vo.CartVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service("cartService")
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    ThreadPoolExecutor executor;

    /**
     * 添加商品到购物车
     * @param skuId
     * @param num
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @Override
    public CartItemVo addProductToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        String res = (String) cartOps.get(skuId.toString());
        if (StringUtils.isEmpty(res)) {
            CartItemVo cartItemVo = new CartItemVo();
            //购物车中没有此商品，执行添加商品操作
            CompletableFuture<Void> getSkuInfo = CompletableFuture.runAsync(() -> {
                //远程调用product查出商品详情
                R r = productFeignService.getSkuInfo(skuId);
                if (r.getCode() == 0) {
                    SkuInfoTo skuInfo = r.getData("skuInfo", new TypeReference<SkuInfoTo>() {
                    });
                    cartItemVo.setCheck(true);
                    cartItemVo.setCount(num);
                    cartItemVo.setSkuId(skuId);
                    cartItemVo.setImage(skuInfo.getSkuDefaultImg());
                    cartItemVo.setTitle(skuInfo.getSkuTitle());
                    cartItemVo.setPrice(skuInfo.getPrice());
                } else {
                    throw new RRException(BizCodeEnum.FEIGN_EXCEPTION.getMsg(), BizCodeEnum.FEIGN_EXCEPTION.getCode());
                }
            }, executor);
            //远程调用product查出商品销售属性组合
            CompletableFuture<Void> getSkuSaleAttrValues = CompletableFuture.runAsync(() -> {
                R r = productFeignService.getSkuSaleAttrValues(skuId);
                if (r.getCode() == 0) {
                    ArrayList<String> skuSaleAttrValues = r.getData(new TypeReference<ArrayList<String>>() {
                    });
                    cartItemVo.setSkuAttr(skuSaleAttrValues);
                }
            }, executor);
            CompletableFuture.allOf(getSkuInfo, getSkuSaleAttrValues).get();
            String cartItemJson = JSON.toJSONString(cartItemVo);
            cartOps.put(skuId.toString(), cartItemJson);
            return cartItemVo;
        } else {
            //购物车中有此商品，增加该商品的数量
            CartItemVo cartItemVo = JSON.parseObject(res, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + num);
            String key = skuId.toString();
            cartOps.put(key, JSON.toJSONString(cartItemVo));

            return cartItemVo;
        }
    }

    /**
     * 获取购物项
     * @param skuId
     * @return
     */
    @Override
    public CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String json = (String) cartOps.get(skuId.toString());
        CartItemVo cartItemVo = JSON.parseObject(json, CartItemVo.class);
        return cartItemVo;
    }

    /**
     * 获取购物车
     * @return
     */
    @Override
    public CartVo getCart(String cookieKey) throws ExecutionException, InterruptedException {
        CartVo cart = new CartVo();
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        //每次获取购物车时，我们需要先获取临时购物车
        List<CartItemVo> tempCartItems = getTempOrUserCartItems(CartConstant.CART_PREFIX + userInfoTo.getUserKey());

        if(userInfoTo.getUserId() != null){
            //1、获取登录用户后的购物车
            List<CartItemVo> userCartItems = getTempOrUserCartItems(CartConstant.CART_PREFIX + userInfoTo.getUserId());
            //2、并且cookies的user-key和当前线程的user-key相等表明是同一个用户，我们就把临时购物车的数据加入到用户购物车
            if(tempCartItems != null && tempCartItems.size() > 0 && cookieKey.equals(userInfoTo.getUserKey())){
                for (CartItemVo tempCartItem : tempCartItems) {
                    addProductToCart(tempCartItem.getSkuId(),tempCartItem.getCount());
                }
                //3、合并之后需要清空临时购物车里的数据
                clearCart(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            }
            //4、获取到合并后的购物车
            List<CartItemVo> mergeTempAndUserCartItems = getTempOrUserCartItems(CartConstant.CART_PREFIX + userInfoTo.getUserId());
            cart.setItems(mergeTempAndUserCartItems);
            return cart;
        }
        cart.setItems(tempCartItems);
        return cart;
    }

    /**
     * 清空购物车
     * @param cartKey 用户标识
     */
    @Override
    public void clearCart(String cartKey) {
        redisTemplate.delete(cartKey);
    }
    /**
     * 修改购物项状态
     * @param skuId
     * @param check
     */
    @Override
    public CartVo checkItem(Long skuId, Integer check) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartVo cartVo = new CartVo();
        //获取指定购物项
        CartItemVo cartItem = getCartItem(skuId);
        //设置属性
        cartItem.setCheck(check==1);
        //转换json
        String cartItemJson = JSON.toJSONString(cartItem);
        String key = skuId.toString();
        //重新放入redis
        cartOps.put(key,cartItemJson);
        //重新获取购物车数据
        List<CartItemVo> tempOrUserCartItems = getTempOrUserCartItems();
        cartVo.setItems(tempOrUserCartItems);
        return cartVo;
    }

    /**
     * 修改商品数量
     * @param skuId
     * @param num
     */
    @Override
    public CartVo countItem(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartVo cartVo = new CartVo();
        //获取指定购物项
        CartItemVo cartItem = getCartItem(skuId);
        //设置属性
        cartItem.setCount(num);
        String cartItemJson = JSON.toJSONString(cartItem);
        String key = skuId.toString();
        //重新放入redis
        cartOps.put(key,cartItemJson);
        //重新获取购物车数据
        List<CartItemVo> tempOrUserCartItems = getTempOrUserCartItems();
        cartVo.setItems(tempOrUserCartItems);
        return cartVo;
    }

    /**
     * 删除指定的购物项
     * @param skuId
     */
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String key = skuId.toString();
        cartOps.delete(key);
    }

    /**
     * 根据用户id获取选中的购物项
     * @param memberId
     * @return
     */
    @Override
    public List<CartItemVo> getUserCartItemsById(Long memberId) {
        String id = memberId.toString();
        String cartKey = CartConstant.CART_PREFIX + id;
        List<CartItemVo> cartItems = getTempOrUserCartItems(cartKey);
        if(cartItems!= null){
            List<Long> ids = cartItems.stream().filter(item -> {
                //返回全部购物车中选中的商品
                return item.getCheck();
            }).map(CartItemVo::getSkuId).collect(Collectors.toList());
            //把每一个的商品的价格重新查询一遍（获取到最新的价格）
            R newPrice = productFeignService.getNewPrice(ids);
            if(newPrice.getCode() == 0){
                List<SkuInfoTo> data = newPrice.getData(new TypeReference<List<SkuInfoTo>>() {});
                Map<Long, BigDecimal> collect = data.stream().collect(Collectors.toMap(SkuInfoTo::getSkuId, SkuInfoTo::getPrice));
                List<CartItemVo> newCartItems = cartItems.stream().map(item -> {
                    BigDecimal price = collect.get(item.getSkuId());
                    item.setPrice(price);
                    return item;
                }).filter(CartItemVo::getCheck).collect(Collectors.toList());
                return newCartItems;
            }else{
                throw new RRException(BizCodeEnum.FEIGN_EXCEPTION.getMsg(),BizCodeEnum.FEIGN_EXCEPTION.getCode());
            }
        }
        return null;
    }


    /**
     * 获取到我们要操作的购物车
     * @return
     */
    public BoundHashOperations<String, Object, Object> getCartOps() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String cartKey = "";
        if (userInfoTo.getUserId() != null) {
            cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserId();
        } else {
            cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
        }
        //每次操作redis（hash）都是根据 cartKey 来操作
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(cartKey);
        return ops;
    }


    /**
     * 根据cartKey获取临时用户 获取 登录用户购物车的购物项
     * @return
     */
    public List<CartItemVo> getTempOrUserCartItems(String cartKey) {
            //每次操作redis（hash）都是根据 cartKey 来操作
            BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(cartKey);
            List<Object> values = ops.values();
            if (values != null && values.size() > 0) {
                List<CartItemVo> collect = values.stream().map(item -> {
                    CartItemVo cartItemVo = JSON.parseObject(item.toString(), CartItemVo.class);
                    return cartItemVo;
                }).collect(Collectors.toList());
                return collect;
            }
            return null;
    }

    /**
     * 获取临时用户 获取 登录用户购物车的购物项
     * @return
     */
    public List<CartItemVo> getTempOrUserCartItems() {
        //每次操作redis（hash）都是根据 cartKey 来操作
        BoundHashOperations<String, Object, Object> ops = getCartOps();
        List<Object> values = ops.values();
        if (values != null && values.size() > 0) {
            List<CartItemVo> collect = values.stream().map(item -> {
                CartItemVo cartItemVo = JSON.parseObject(item.toString(), CartItemVo.class);
                return cartItemVo;
            }).collect(Collectors.toList());
            return collect;
        }
        return null;
    }
}
